package com.link.base.wechat.wxtoken.service;

import com.link.base.wechat.thirdparty.util.WxThirdPartyUtil;
import com.link.base.wechat.wxlog.model.WxLogModule;
import com.link.base.wechat.wxlog.service.WxLogService;
import com.link.base.wechat.wxplatform.model.WxPlatform;
import com.link.base.wechat.wxplatform.service.WxPlatformService;
import com.link.base.wechat.wxtoken.model.WxJsTicket;
import com.link.base.wechat.wxtoken.model.WxToken;
import com.link.base.wechat.wxtoken.util.WxTokenUtil;
import com.link.core.basic.service.BasicServiceException;
import com.link.core.basic.service.BasicServiceImpl;
import com.link.core.basic.service.ServiceException;
import com.link.core.util.DateUtil;
import com.link.core.util.RedisUtil;
import com.link.base.core.basic.util.YmlConstants;
import com.link.core.util.redisclient.LinkRedisClient;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
 * 微信公众号Token服务
 *
 * @author ouyangzhenqiang
 * @date 2019/02/26 15:36
 */
@Service
public class WxTokenServiceImpl extends BasicServiceImpl<WxPlatform> implements WxTokenService {
    /**
     * 公众号access_token redisKey前缀
     */
    private static final String WX_PLATFORM_TOKEN_REDIS_KEY = "wx_platform_token_";
    /**
     * 公众号jsTicket redisKey前缀
     */
    private static final String WX_PLATFORM_JS_TICKET_REDIS_KEY = "wx_platform_jsTicket_";
    /**
     * access_token/jsTicket有效期
     */
    private static final int WX_EXPIRE_TIME = 7200;
    /**
     * 第三方平台下的授权公众号信息redisKey前缀
     */
    private static final String AUTHORIZATION_WX_APP_REDIS_KEY = "Authorization_";
    /**
     * 魔法值
     */
    private static final String Y_STR = "Y";

    @Resource
    private WxLogService wxLogService;
    @Resource
    private WxPlatformService wxPlatformService;

    @Override
    public WxToken refreshWxTokenByAppId(String wxAppId) throws Exception {
        if (StringUtils.isBlank(wxAppId)) {
            throw new ServiceException("WXTOKEN-001！");
        }
        WxPlatform wxPlatform = wxPlatformService.getWxPlatformByAppId(wxAppId);
        LinkRedisClient j = null;
        WxToken wxToken;
        try {
            j = RedisUtil.getJedis();
            wxToken = getAccessTokenByWxPlatform(wxPlatform, j);
        } finally {
            RedisUtil.returnResource(j);
        }
        return wxToken;
    }

    @Override
    public void refreshAllWxToken() throws Exception {
        List<WxPlatform> wxPlatformList = wxPlatformService.queryAllNoCorp();
        String wxAppId = "";
        Long cropId = 0L;
        LinkRedisClient j = null;
        try {
            j = RedisUtil.getJedis();
            for (WxPlatform item: wxPlatformList) {
                wxAppId = item.getWx_app_id();
                cropId = item.getCorpid();
                try {
                    getAccessTokenByWxPlatform(item, j);
                } catch (Exception e) {
                    wxLogService.error(WxLogModule.wxLogToken, "刷新access_token",
                        "定时刷新Token失败 => " + e.getMessage(), wxAppId, cropId);
                }
            }
        } finally {
            RedisUtil.returnResource(j);
        }
    }

    @Override
    public WxToken getWxAccessTokenByAppId(String wxAppId) throws Exception {
        if (StringUtils.isBlank(wxAppId)) {
            throw new BasicServiceException("wxAppId参数不能为空！");
        }
        WxToken wxToken = new WxToken();
        LinkRedisClient j = null;
        try {
            j = RedisUtil.getJedis();
            String redisKey = WX_PLATFORM_TOKEN_REDIS_KEY + wxAppId;
            String accessToken = j.hget(redisKey, "access_token");
            if (StringUtils.isBlank(accessToken)) {
                wxToken = refreshWxTokenByAppId(wxAppId);
            } else {
                // 对刷新时间做补充判断，防止定时刷新工作流挂掉之后，导致token不会刷新
                String refresh_time = j.hget(redisKey, "refresh_time");
                Date oldDate = DateUtil.stringToDate(refresh_time, "yyyy-MM-dd HH:mm:ss");
                Date currentDate = new Date();
                int v1000 = 1000;
                int v7200 = 7200;
                if (((currentDate.getTime() - oldDate.getTime()) / v1000) > v7200 ) {
                    wxToken = refreshWxTokenByAppId(wxAppId);
                } else {
                    wxToken.setAccess_token(accessToken);
                    wxToken.setWxAppId(j.hget(redisKey, "wx_app_id"));
                    wxToken.setRefresh_time(refresh_time);
                    wxToken.setCorpid(Long.parseLong(j.hget(redisKey, "corp_id")));
                }
            }
        } finally {
            RedisUtil.returnResource(j);
        }
        return wxToken;
    }

    @Override
    public WxJsTicket getWxJsTicketByAppId(String wxAppId) throws Exception {
        return getJsTicketByAppId(wxAppId, "jsapi");
    }

    @Override
    public WxJsTicket getXcxJsTicketByAppId(String wxAppId) throws Exception {
        return getJsTicketByAppId(wxAppId, "wx_card");
    }

    /**
     * 获取js_ticket
     *
     * @author ouyangzhenqiang
     * @date 2019/03/19 19:41
     * @param wxAppId 微信公众号应用Id
     * @param type ticket类型  jsapi/wx_card
     */
    private WxJsTicket getJsTicketByAppId(String wxAppId, String type) throws Exception {
        if (StringUtils.isBlank(wxAppId)) {
            throw new ServiceException("WXTOKEN-002");
        }
        WxJsTicket wxJsTicket = new WxJsTicket();
        LinkRedisClient j = null;
        try {
            j = RedisUtil.getJedis();
            String redisKey = WX_PLATFORM_JS_TICKET_REDIS_KEY + wxAppId + "_" + type;
            String jsTicket = j.hget(redisKey, "js_ticket");
            if (StringUtils.isBlank(jsTicket)) {
                WxPlatform wxPlatform = wxPlatformService.getWxPlatformByAppId(wxAppId);
                jsTicket = WxTokenUtil.getJsTicketByAccessToken(getWxAccessTokenByAppId(wxAppId).getAccess_token(), type);
                j.hset(redisKey, "wx_app_id", wxAppId);
                j.hset(redisKey, "js_ticket", jsTicket);
                j.hset(redisKey, "refresh_time", DateUtil.dateToStr(new Date(),"yyyy-MM-dd HH:mm:ss"));
                j.hset(redisKey, "corp_id", String.valueOf(wxPlatform.getCorpid()));
                j.expire(redisKey, WX_EXPIRE_TIME);
                wxLogService.log(WxLogModule.wxLogToken, "刷新JsTicket",
                    "新JsTicket为 => " + jsTicket, wxAppId, wxPlatform.getCorpid());
            }
            wxJsTicket.setJs_ticket(jsTicket);
            wxJsTicket.setWxAppId(j.hget(redisKey, "wx_app_id"));
            wxJsTicket.setRefresh_time(j.hget(redisKey, "refresh_time"));
            wxJsTicket.setCorpid(Long.parseLong(j.hget(redisKey, "corp_id")));
        } finally {
            RedisUtil.returnResource(j);
        }
        return wxJsTicket;
    }

    /**
     * 获取access_token通过wxPlatform
     *
     * @author ouyangzhenqiang
     * @date 2019/02/27 17:39
     * @param record 公众号对象
     * @param j redis连接
     */
    private WxToken getAccessTokenByWxPlatform(WxPlatform record, LinkRedisClient j) throws Exception {
        if (!Y_STR.equals(record.getValid_flag())) {
            throw new ServiceException("WXTOKEN-003", record.getWx_pp_accntname(), record.getWx_app_id());
        }
        String mode;
        String access_token_new;
        String isDevMode = record.getIs_dev_mode();
        if (Y_STR.equals(isDevMode)) {
            mode = "开发模式";
            String wxAppId = record.getWx_app_id();
            String wxAppSecret = record.getWx_app_secret();
            access_token_new = WxTokenUtil.getAccessTokenBySecret(wxAppId, wxAppSecret);
        } else {
            mode = "第三方平台模式";
            String componentAppId = YmlConstants.getWxComponentAppId();
            String componentAccessToken = WxThirdPartyUtil.getComponentAccessToken();
            String authorizerRefreshToken = j.hget(AUTHORIZATION_WX_APP_REDIS_KEY + record.getWx_app_id(), "authorizer_refresh_token");
            access_token_new = WxTokenUtil.getAccessTokenByComponent(
                componentAppId, componentAccessToken, record.getWx_app_id(), authorizerRefreshToken);
        }
        String redisKey = WX_PLATFORM_TOKEN_REDIS_KEY + record.getWx_app_id();
        String refreshTime = DateUtil.dateToStr(new Date(),"yyyy-MM-dd HH:mm:ss");
        Long corpId = record.getCorpid();
        String wxAppId = record.getWx_app_id();
        j.hset(redisKey, "wx_app_id", wxAppId);
        j.hset(redisKey, "access_token", access_token_new);
        j.hset(redisKey, "refresh_time", refreshTime);
        j.hset(redisKey, "corp_id", String.valueOf(corpId));
        j.expire(WX_PLATFORM_TOKEN_REDIS_KEY + record.getWx_app_id(), WX_EXPIRE_TIME);
        wxLogService.log(WxLogModule.wxLogToken, mode + "刷新access_token",
            "新access_token为 => " + access_token_new, wxAppId, corpId);
        WxToken wxToken = new WxToken();
        wxToken.setWxAppId(wxAppId);
        wxToken.setAccess_token(access_token_new);
        wxToken.setCorpid(corpId);
        wxToken.setRefresh_time(refreshTime);
        return wxToken;
    }
}
